package com.android.music2;

import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;

public class ExtendedAudioProvider extends ContentProvider 
{
    
    //The current database version
	private static final int DATABASE_VERSION = 3;
    
	public static final String PROVIDER_NAME = 
        "com.android.music2.ExtendedAudioProvider";
     
     public static final Uri CONTENT_URI_SONGS = 
        Uri.parse("content://"+ PROVIDER_NAME + "/song");
     public static final Uri CONTENT_URI_FOLDERS = 
         Uri.parse("content://"+ PROVIDER_NAME + "/playlist_folder");
     public static final Uri CONTENT_URI_FOLDERS_MAP = 
         Uri.parse("content://"+ PROVIDER_NAME + "/playlist_folder_map");
     
     //Song table columns
     public static final String _ID = "_id";
     public static final String ORIGINAL_ID = "original_id"; 
     public static final String RATING = "rating";     
     public static final String PLAY_COUNT = "play_count";
     public static final String DATE_LASY_PLAY = "date_last_play";
     public static final String WIKI_URL = "wiki_url";
     public static final String SAVED_WIKI_FILE_LOCATION = "saved_wiki_file";
     public static final String LYRICS = "lyrics";
     public static final String HIP_AGAIN = "is_hip";
     
     public static final String FOLDER_NAME = "name";
     
     public static final String FOLDER_ID = "folder_id";
     public static final String PLAYLIST_NAME = "name";
     
     private static final int SONGS = 1;
     private static final int SONG_ID = 2;  
     private static final int PLAYLIST_FOLDERS = 3;
     private static final int PLAYLIST_FOLDER_ID = 4;
     private static final int PLAYLIST_FOLDERS_MAP = 5;
     private static final int PLAYLIST_FOLDER_MAP_ID = 6;
        
     private static final UriMatcher uriMatcher;
     static{
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(PROVIDER_NAME, "song", SONGS);
        uriMatcher.addURI(PROVIDER_NAME, "song/#", SONG_ID);  
        uriMatcher.addURI(PROVIDER_NAME, "playlist_folder", PLAYLIST_FOLDERS);
        uriMatcher.addURI(PROVIDER_NAME, "playlist_folder/#", PLAYLIST_FOLDER_ID); 
        uriMatcher.addURI(PROVIDER_NAME, "playlist_folder_map", PLAYLIST_FOLDERS_MAP);
        uriMatcher.addURI(PROVIDER_NAME, "playlist_folder_map/#", PLAYLIST_FOLDER_MAP_ID); 
     }
     
     //---for database use---
     private SQLiteDatabase extendedDB;
     private static final String DATABASE_NAME = "extended-audio.db";
     
     private static final String SONGS_TABLE = "songs";
     private static final String PLAYLIST_FOLDERS_TABLE = "playlist_folders";
     private static final String PLAYLIST_FOLDERS_MAP_TABLE = "playlist_folders_map";
     
     //HIP_AGAIN just added as a test on database upgrades, not used by the app
     private static final String SONGS_TABLE_CREATE =
           "create table " + SONGS_TABLE 
           + " (" + _ID + " integer primary key, "
           + ORIGINAL_ID + " integer, "
           + RATING + " integer, " 
           + PLAY_COUNT + " integer, "
           + DATE_LASY_PLAY + " integer, "
           + WIKI_URL + " text, " 
           + SAVED_WIKI_FILE_LOCATION + " text, "
           + LYRICS + " text, "
           + HIP_AGAIN + " integer;";
     
     private static final String PLAYLIST_FOLDERS_TABLE_CREATE =
         "create table " + PLAYLIST_FOLDERS_TABLE 
         + " (" + _ID + " integer primary key, "
         + FOLDER_NAME + " text);";
     
     //ID must be the original_id of the playlist from the media provider
     private static final String PLAYLIST_FOLDERS_MAP_TABLE_CREATE =
         "create table " + PLAYLIST_FOLDERS_MAP_TABLE 
         + " (" + _ID + " integer primary key, "
         + FOLDER_ID + " integer, "
         //+ ORIGINAL_ID + " integer, "
         + PLAYLIST_NAME + " text);";
     
     
     private static final String CREATE_FOLDERS_1 = 
    	 "insert into " + PLAYLIST_FOLDERS_TABLE + 
    	 " values (1,'Auto Playlists');";
     private static final String CREATE_FOLDERS_2 = 
    	 "insert into " + PLAYLIST_FOLDERS_TABLE + 
    	 " values (2,'My Playlists');";
    	 
     private static class DatabaseHelper extends SQLiteOpenHelper 
     {
        
    	 private Context mContext;
    	 DatabaseHelper(Context context) {
           super(context, DATABASE_NAME, null, DATABASE_VERSION);
           mContext = context;
        }

        @Override
        public void onCreate(SQLiteDatabase db) 
        {
           //On a clean install need to include all the steps that the upgrades would do
           db.execSQL(SONGS_TABLE_CREATE);
           db.execSQL(PLAYLIST_FOLDERS_TABLE_CREATE);
           db.execSQL(PLAYLIST_FOLDERS_MAP_TABLE_CREATE);
           db.execSQL(CREATE_FOLDERS_1);
           db.execSQL(CREATE_FOLDERS_2);
           importExistingPlaylistsToFolderMap(db);           
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    		if(oldVersion == 1) {
    			//The changes needed to go from version 1 to the current version
    		    db.execSQL("ALTER TABLE " + SONGS_TABLE + " ADD COLUMN " + HIP_AGAIN + " integer");
    		    db.execSQL(PLAYLIST_FOLDERS_TABLE_CREATE);
    	        db.execSQL(PLAYLIST_FOLDERS_MAP_TABLE_CREATE);
    	        db.execSQL(CREATE_FOLDERS_1);
    	        db.execSQL(CREATE_FOLDERS_2);
    		} else if (oldVersion == 2) {
    			//The changes needed to go from version 2 to the current version
    			importExistingPlaylistsToFolderMap(db);   
    		} else {
    			db.execSQL("DROP TABLE IF EXISTS " + SONGS_TABLE + ";");
    			onCreate(db);
    		}
        }
        
        private void importExistingPlaylistsToFolderMap(SQLiteDatabase db) {
	        //Get all the existing playlist ids and add them into the 
			// playlist_folder_map for folder 2 (My Playlists)
	        String[] cols = new String[] {
	                MediaStore.Audio.Playlists._ID,
	                MediaStore.Audio.Playlists.NAME 
	        };
	        ContentResolver resolver = mContext.getContentResolver();
	        String whereclause = MediaStore.Audio.Playlists.NAME + " != ''";
	        Cursor cur = resolver.query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
	                cols, whereclause, null, null);
	        
	        int len = cur.getCount();
	        cur.moveToFirst();
	        for (int i = 0; i < len; i++) {    	       	        	
	        	//Check if this playlist is already in the folder map
	        	Cursor c = db.query(PLAYLIST_FOLDERS_MAP_TABLE, new String[]{_ID}, _ID + "=" + cur.getLong(cur.getColumnIndex(MediaStore.Audio.Playlists._ID)), null, null, null, null);
	        	if(c.getCount() == 0) {    	        	
    	        	//If not, then add it in
    	        	db.execSQL("INSERT INTO " + PLAYLIST_FOLDERS_MAP_TABLE 
    	        			+ " VALUES (" + cur.getLong(cur.getColumnIndex(MediaStore.Audio.Playlists._ID)) 
    	        			+ ", 2, '" + cur.getString(cur.getColumnIndex(MediaStore.Audio.Playlists.NAME)) + "');");
	        	}
	        	c.close();
	        	cur.moveToNext();
	        }
	        cur.close();
        }
     }  
	
	
   @Override
   public int delete(Uri arg0, String arg1, String[] arg2) {
	      // arg0 = uri 
	      // arg1 = selection
	      // arg2 = selectionArgs
	      int count=0;
	      switch (uriMatcher.match(arg0)){
	         case SONGS:
	            count = extendedDB.delete(
	            		SONGS_TABLE,
	               arg1, 
	               arg2);
	            break;
	         case SONG_ID:
	            String id = arg0.getPathSegments().get(1);
	            count = extendedDB.delete(
	            		SONGS_TABLE,                        
	               _ID + " = " + id + 
	               (!TextUtils.isEmpty(arg1) ? " AND (" + 
	               arg1 + ')' : ""), 
	               arg2);
	            break;
	         case PLAYLIST_FOLDERS:
		            count = extendedDB.delete(
		            		PLAYLIST_FOLDERS_TABLE,
		               arg1, 
		               arg2);
		            break;
	         case PLAYLIST_FOLDER_ID:
		            String fid = arg0.getPathSegments().get(1);
		            count = extendedDB.delete(
		            		PLAYLIST_FOLDERS_TABLE,                        
		               _ID + " = " + fid + 
		               (!TextUtils.isEmpty(arg1) ? " AND (" + 
		               arg1 + ')' : ""), 
		               arg2);
	         case PLAYLIST_FOLDERS_MAP:
		            count = extendedDB.delete(
		            		PLAYLIST_FOLDERS_MAP_TABLE,
		               arg1, 
		               arg2);
		            break;
	         case PLAYLIST_FOLDER_MAP_ID:
		            String fmid = arg0.getPathSegments().get(1);
		            count = extendedDB.delete(
		            		PLAYLIST_FOLDERS_MAP_TABLE,                        
		               _ID + " = " + fmid + 
		               (!TextUtils.isEmpty(arg1) ? " AND (" + 
		               arg1 + ')' : ""), 
		               arg2);
	         default: throw new IllegalArgumentException(
	            "Unknown URI " + arg0);    
	      }       
	      getContext().getContentResolver().notifyChange(arg0, null);
	      return count;  
   }

   @Override
   public String getType(Uri uri) {
	      switch (uriMatcher.match(uri)){
	         //---get all songs---
	         case SONGS:
	            return "vnd.android.cursor.dir/vnd.android.music2.songs ";
	         //---get a particular song---
	         case SONG_ID:                
	            return "vnd.android.cursor.item/vnd.android.music2.songs ";
	         case PLAYLIST_FOLDERS:
		            return "vnd.android.cursor.dir/vnd.android.music2.playlist_folders ";
		     case PLAYLIST_FOLDER_ID:                
		            return "vnd.android.cursor.item/vnd.android.music2.playlist_folder ";
	         case PLAYLIST_FOLDERS_MAP:
		            return "vnd.android.cursor.dir/vnd.android.music2.playlist_folders_map ";
		     case PLAYLIST_FOLDER_MAP_ID:                
		            return "vnd.android.cursor.item/vnd.android.music2.playlist_folder_map ";
	         default:
	            throw new IllegalArgumentException("Unsupported URI: " + uri);        
	      } 
   }

   @Override
   public Uri insert(Uri uri, ContentValues values) {
	      //---add a new song---
	   
	   if (uriMatcher.match(uri) == SONGS) {
	   
	      long rowID = extendedDB.insert(
	    		  SONGS_TABLE, "", values);
	           
	      //---if added successfully---
	      if (rowID>0)
	      {
	    	  Uri _uri = ContentUris.withAppendedId(CONTENT_URI_SONGS, rowID);
	         getContext().getContentResolver().notifyChange(_uri, null);    
	         return _uri;                
	      }        
	   } 
	   
	   if (uriMatcher.match(uri) == PLAYLIST_FOLDERS) {
		   
		      long rowID = extendedDB.insert(
		    		  PLAYLIST_FOLDERS_TABLE, "", values);
		           
		      //---if added successfully---
		      if (rowID>0)
		      {
		    	  Uri _uri = ContentUris.withAppendedId(CONTENT_URI_FOLDERS, rowID);
		         getContext().getContentResolver().notifyChange(_uri, null);    
		         return _uri;                
		      }        
		} 
	   
	   if (uriMatcher.match(uri) == PLAYLIST_FOLDERS_MAP) {
		   
		      long rowID = extendedDB.insert(
		    		  PLAYLIST_FOLDERS_MAP_TABLE, "", values);
		           
		      //---if added successfully---
		      if (rowID>0)
		      {
		    	  Uri _uri = ContentUris.withAppendedId(CONTENT_URI_FOLDERS_MAP, rowID);
		         getContext().getContentResolver().notifyChange(_uri, null);    
		         return _uri;                
		      }        
		} 
	   
	      throw new SQLException("Failed to insert row into " + uri);

   }

   @Override
   public boolean onCreate() {
	      Context context = getContext();
	      DatabaseHelper dbHelper = new DatabaseHelper(context);
	      extendedDB = dbHelper.getWritableDatabase();
	      return extendedDB != null;

   }

   @Override
   public Cursor query(Uri uri, String[] projection, String selection,
         String[] selectionArgs, String sortOrder) {
	   
	      SQLiteQueryBuilder sqlBuilder = new SQLiteQueryBuilder();
	      if (uriMatcher.match(uri) == SONG_ID || uriMatcher.match(uri) == SONGS) {
	      sqlBuilder.setTables(SONGS_TABLE);
	      } else if (uriMatcher.match(uri) == PLAYLIST_FOLDER_ID || uriMatcher.match(uri) == PLAYLIST_FOLDERS) {
	    	  sqlBuilder.setTables(PLAYLIST_FOLDERS_TABLE);
	      } else {
	    	  sqlBuilder.setTables(PLAYLIST_FOLDERS_MAP_TABLE);
	      }
	       
	      if (uriMatcher.match(uri) == SONG_ID 
	    		  || uriMatcher.match(uri) == PLAYLIST_FOLDER_ID
	    		  || uriMatcher.match(uri) == PLAYLIST_FOLDER_MAP_ID) {
	         //---if getting a particular song or folder---
	         sqlBuilder.appendWhere(
	            _ID + " = " + uri.getPathSegments().get(1));                
	      }   
	      
	      if (sortOrder==null || sortOrder=="") {
	         sortOrder = _ID;
	      }
	      
	    String limit = uri.getQueryParameter("limit");
		Cursor c = sqlBuilder.query(
	         extendedDB, 
	         projection, 
	         selection, 
	         selectionArgs, 
	         null, 
	         null, 
	         sortOrder,
	         limit );
	   
	      //---register to watch a content URI for changes---
	      c.setNotificationUri(getContext().getContentResolver(), uri);
	      return c;

   }

   @Override
   public int update(Uri uri, ContentValues values, String selection,
         String[] selectionArgs) {
	      int count = 0;
	      switch (uriMatcher.match(uri)){
	         case SONGS:
	            count = extendedDB.update(
	            		SONGS_TABLE, 
	               values,
	               selection, 
	               selectionArgs);	  
	            break;
	         case SONG_ID:                
	            count = extendedDB.update(
	            		SONGS_TABLE, 
	               values,
	               _ID + " = " + uri.getPathSegments().get(1) + 
	               (!TextUtils.isEmpty(selection) ? " AND (" + 
	                  selection + ')' : ""), 
	                selectionArgs);
	            break;
	         case PLAYLIST_FOLDERS:
		            count = extendedDB.update(
		            		PLAYLIST_FOLDERS_TABLE, 
		               values,
		               selection, 
		               selectionArgs);	  
		            break;
		         case PLAYLIST_FOLDER_ID:                
		            count = extendedDB.update(
		            		PLAYLIST_FOLDERS_TABLE, 
		               values,
		               _ID + " = " + uri.getPathSegments().get(1) + 
		               (!TextUtils.isEmpty(selection) ? " AND (" + 
		                  selection + ')' : ""), 
		                selectionArgs);
		            break;
		         case PLAYLIST_FOLDERS_MAP:
			            count = extendedDB.update(
			            		PLAYLIST_FOLDERS_MAP_TABLE, 
			               values,
			               selection, 
			               selectionArgs);	  
			            break;
			         case PLAYLIST_FOLDER_MAP_ID:                
			            count = extendedDB.update(
			            		PLAYLIST_FOLDERS_MAP_TABLE, 
			               values,
			               _ID + " = " + uri.getPathSegments().get(1) + 
			               (!TextUtils.isEmpty(selection) ? " AND (" + 
			                  selection + ')' : ""), 
			                selectionArgs);
			            break;
	         default: throw new IllegalArgumentException(
	            "Unknown URI " + uri);    
	      }       
	      getContext().getContentResolver().notifyChange(uri, null);
	      return count;

   }
}
 



